//FPV-BASE 1.0
	
	
/*	Ejemplo de una sentencia NMEA de tipo $GPRMC
	
	$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A

			RMC          Recommended Minimum sentence C
			123519       Fix taken at 12:35:19 UTC
			A            Status A=active or V=Void.
			4807.038,N   Latitude 48 deg 07.038' N
			01131.000,E  Longitude 11 deg 31.000' E
			022.4        Speed over the ground in knots
			084.4        Track angle in degrees True
			230394       Date - 23rd of March 1994
			003.1,W      Magnetic Variation
			*6A          The checksum data, always begins with *
		
*/
	
	
	
	#include "TinyGPSMod.h"
	#include <NewSoftSerialMod.h>
	#include <LiquidCrystal.h>
	#include <Tone.h>
	#include <EEPROM.h> 	
	
	
	// Constantes
	const int BUZZER = 14;								// Pin donde esta el buzzer
	const int BATERIA = 5;								// Pin donde esta el voltimero de la bateria
	
	const float BATALERTA = 11.00;  					// Para alarma de bateria baja
	const float BATALARMA = 10.50;						// Para alarma de bateria muy baja
	
	const int MEM_LAT = 10;								// Posicion EEPROM para la LATITUD
	const int MEM_LON = 14;								// Posicion EEPROM para la LONGITUD
	
	
	// Definiciones de Objetos 
	LiquidCrystal lcd(8, 9, 10, 11, 12, 13);			// El display LCD
	TinyGPSMod migps;									// Es gestor de sentencias NMEA
	NewSoftSerialMod nss(2, 3);							// Las comunicaciones con el GPS
	Tone zumbador;										// Pitidos. (1000Hz son suaves. De 1800 Hz los que mas suenan).
	

	// Definicion de funciones que si no no se ven bien (no se muy bien por que)
	// Funciones para escribir y leer datos mayores de byte (long por ejemplo) en la EEPROM
	template <class T> int EEPROM_escribe(int ee, const T& value);		
	template <class T> int EEPROM_lee(int ee, T& value);
	
	
	// Variables cambiantes de programa
	float tension = 0;									// Almacena la tension de la bateria de tierra
	int cicloprograma = 0;								// Define en que ciclo esta el programa
	int recibiendo = 0;									// 0 = Esperando primera senal. 1 = recibiendo. 2 = Senal perdida
	long lat, lon;										// Para almnacenar las coordenadas
	unsigned long fix;									// Para almacenar la hora de FIX de la posicion
	bool v_alerta = false;								// Flag de alerta de tension baja
	bool v_alarma = false;								// Flag de alarma de tension baja
	bool g_alerta = false;								// Flag de alerta de posicion perdida
	
	
	void setup(){										// ### RUTINA DE CONFIGURACION
	
		pinMode(BUZZER, OUTPUT);						// Pin del zumbador como salida
			
		lcd.begin(2, 16);								// Inicializar LCD de 2 filas, 16 columnas
		Serial.begin(57600);							// Iniciar puero de comunicaciones
		nss.begin(57600);								// Inicializar comunicaciones con GPS a 57600
		zumbador.begin(BUZZER);							// Inicializar objeto generador de sonido en el pin BUZZER
		
		EEPROM_lee(MEM_LAT, lat);						// Leer las posiciones almacenadas en EEPROM (ultimas conocidas)
		EEPROM_lee(MEM_LON, lon);
		
		Serial.println("ESTACION FPV 1.0 OK");			// Mensage por el serie
		
		lcd.print("FPV BASE  1.0 OK");					// Mensaje por LCD
			
		delay(2000);			
													
		lcd.setCursor(0, 1);							// Pitido de ejemplo de Senal GPS Perdida.
		lcd.print(" ALERTA POS GPS ");
		pitar(1000, 100, 2, 100);							
		delay(2000);
		
		lcd.setCursor(0, 1);							// Pitido de ejemplo de alerta de bateria baja.
		lcd.print(" ALERTA BATERIA ");
		pitar(1000, 300, 2, 200);								
		delay(2000);
		
		lcd.setCursor(0, 1);							// Pitido de ejemplo de alarma de bateria baja.
		lcd.print(" ALARMA BATERIA ");
		pitar(1800, 1000, 1, 0);									
		delay(2000);
		
		lcd.clear();
	}
	
	
	
	void loop(){										// ### BUCLE PRINCIPAL DE PROGRAMA
	
	
		bool newdata = false;							// Flag que indica sentencia NMEA completa recibida
		unsigned long start = millis();					// Cojer tiempo actual de ejecucion del programa

		while (millis() - start < 3000){				// Este ciclo es rapido y se sale cada XXXX ms
														
			if (feedgps()) newdata = true;				// Alimentar el GPS con datos ectivar flag cuando se complete una sentencia NMEA
			
		}
		
	
		lcd.clear();
		
		switch (cicloprograma) {								// Cada ciclo hacemos una cosa. He comentado las alimentaciones del GPS para que no molesten.
		
			case 0:												// Ciclo 0, comprobar baterias
	
				tension = leevoltimetro(BATERIA, 14);			// Leer la tension
				//feedgps();
					
				if (tension < BATALERTA) {						// Comprar con la alerta
		
					lcd.print("  BATERIA BAJA  ");
					v_alerta = true;
					v_alarma = false;
					
				}
		
				else if (tension < BATALARMA) {					// Comprar con alarma
		
					lcd.print("BATERIA MUY BAJA");
					v_alerta = false;
					v_alarma = true;
		
				}
		
				else {											// Si no hay alerta ni alarma ...
		
					lcd.print(" BATERIA NORMAL ");
					v_alerta = false;
					v_alarma = false;
		
				}
		
				//feedgps();
				lcd.setCursor(0, 1);							// escribir el MSG en el LCD
				lcd.print("TENSION: ");
				if (tension < 10.00) lcd.print("0");
				lcd.print(tension);
				lcd.print(" V");
				//feedgps();
				break;
		
		
		
			case 1:												// Ciclo 1, coordenadas
			
	
				if (newdata){									// Si tenemos sentencia NMEA completa ....
    
					if ( recibiendo != 1 ) {					// Si todavia no habiamos recibido ninguna NMEA valida .....
												
						pitar(1000, 100, 2, 100);				// Pitar para informar que ya la tenemos	
						recibiendo = 1;							
						g_alerta = false;						// Apagar el flag de alerta	
						EEPROM_escribe(MEM_LAT, lat);			// Almacenar posiciones en el EEPROM
						EEPROM_escribe(MEM_LON, lon);
																		
					}
					
					lcd.print(" RECIBIENDO GPS ");				// Msg ...
					
				}
		
				else {											// Si no tenemos sentencia NMEA
				
				
					if ( recibiendo == 0 ) lcd.print (" ESPERANDO  GPS ");	// Si el ciclo anterior tampoco
				
					if ( recibiendo == 1 ){
				
						EEPROM_escribe(MEM_LAT, lat);
						EEPROM_escribe(MEM_LON, lon);
						
						lcd.print (" SE HA PERDIDO  ");
						lcd.setCursor(0, 1);
						lcd.print ("LA POSICION GPS");
						g_alerta = true;
				
					}
				
				}
								
				//feedgps();
				break;
		
		
		
			case 2:
			
				if (newdata) migps.get_position(&lat, &lon, &fix);
				
				lcd.print("LAT: ");
				lcd.print(lat);
				lcd.setCursor(0, 1);
				lcd.print("LON: ");
				lcd.print(lon);
				
				//feedgps();
				
				if (!newdata) cicloprograma++;	// Si no hay dato saltarse el paso 3
				break;
			
			
			case 3:
			
				lcd.clear();
				lcd.print("RUM: ");
				lcd.print(migps.course());
				lcd.print("ALT: ");
				lcd.print(migps.altitude() / 100);
				lcd.setCursor(0, 1);
				lcd.print("VEL: ");
				lcd.print(migps.speed());
				
				//feedgps();
				break;
				
		}
		
		if (cicloprograma == 3) { cicloprograma = 0;}				// Para incremenbtar el contador de ciclo
		else {cicloprograma++;}
	
	
		if (g_alerta) { pitar(1000, 100, 2, 100);}		// ALARMAS Y ALERTAS
		if (v_alerta) { pitar(1000, 300, 2, 200);}		
		if (v_alarma) { pitar(1800, 1000, 1, 0);}		
	

	}

	
	bool feedgps(){
  
  
			while (nss.available()){
  
				char c = nss.read();
				//Serial.print(c);
				if (migps.encode(c)) {return true;}
	  
			}
  
			return false;
		
	}
	
	
	
/*
	void printdato (TinyGPSMod &gpsobj) {
	
		long lat, lon;
		unsigned long fix, fecha, hora, chars;
		//int ano;
		//byte month, day, hour, minute, second, hundredths;
		unsigned short sentences, fallidas;
	
		Serial.println(" ");
		Serial.println("ESTADO DEL GPS ...");
		Serial.println("------------------");
		
		gpsobj.get_position(&lat, &lon, &fix);
	
		Serial.print("Lat/Long: "); Serial.print(lat); Serial.print(", "); Serial.println(lon); 
		Serial.print("Fix     : "); Serial.print(fix); Serial.println("ms.");
	
		feedgps();
		
		Serial.print("Alt(cm): "); Serial.println(gpsobj.altitude()); 
		Serial.print("Rumbo  : "); Serial.println(gpsobj.course()); 
		Serial.print("VNudos : "); Serial.println(gpsobj.speed());
		
		feedgps();

		gpsobj.stats(&chars, &sentences, &fallidas);
		Serial.print("Chars  : "); Serial.println(chars); 
		Serial.print("Sent.  : "); Serial.println(sentences); 
		Serial.print("Fallos : "); Serial.println(fallidas);
		Serial.println("------------------");
		Serial.println(" ");
	}

*/
	
	void pitar(int frecuencia, int duracion, int veces, int espacio) {
	
		nss.rxoff(true);	// Parar RX
		
		while (veces > 0) {
	
			zumbador.play(frecuencia, duracion);
			delay(duracion + espacio);
		
		veces--;
	
		}
		
		nss.rxoff(false);	// Restablecer RX
		
	}
	
	
	float leevoltimetro (int entrada, int valmax) {	// lee una entrada analogica y devuelve el valor real (en funcion al valmax que es el valor que corresponde a 5V)
	
		int lectura;
	
		float factor = float(valmax) / 1023.00;	// Calculo del factor. Fijarse en la conversion de valmax a float y los fijos que llevan coma
		lectura = analogRead(entrada);
		return float(lectura) * factor;
		
	}
	
	
	template <class T> int EEPROM_escribe(int ee, const T& value){
	
		const byte* p = (const byte*)(const void*)&value;
		int i;
		for (i = 0; i < sizeof(value); i++) EEPROM.write(ee++, *p++);
		return i;
	
	}

	template <class T> int EEPROM_lee(int ee, T& value) {
	
		byte* p = (byte*)(void*)&value;
		int i;
		for (i = 0; i < sizeof(value); i++) *p++ = EEPROM.read(ee++);
		return i;
	
	}
